﻿using System;
using System.Collections.Generic;
using System.Drawing;
using iTextSharp.text;
using iTextSharp.text.pdf;
using Common;
using System.IO;
using Font = iTextSharp.text.Font;

namespace Web.Helpers
{
    //Keep in mind that in PDF 0,0 is the lower left corner, and coordinates increase as you go right and UP.
    public class PdfHelper
    {
        public PdfHelper()
        {
            var baseFont = BaseFont.CreateFont(@"C:\WINDOWS\Fonts\arial.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
            var defaultFont = new Font(baseFont, 10f, Font.NORMAL, new BaseColor(Color.Black) );
            var defaultCell = new CellStyle
            {
                //Font =  new CellStyle.CellFont()
                //        {
                //            Family = Font.FontFamily.HELVETICA,
                //            Size = 10f,
                //            Type = CellStyle.CellFont.FontType.Normal,
                //            ForeColor = Color.Black,
                //            BackColor = Color.White
                //        },
                Font = new CellStyle.CellFont() { Family = defaultFont.Family, Size = defaultFont.Size, Type = CellStyle.CellFont.FontType.Normal, ForeColor = Color.Black, BackColor = Color.White },
                Border = new CellStyle.BorderStyle() {Color = System.Drawing.Color.Black, Widths = new TopLeftRightBottom() { Bottom = 0.5f, Left = 0.5f, Top = 0.5f, Right = 0.5f } },
                Span = new CellStyle.CellSpan() {Cols = 1, Rows = 1},
                Padding = new CellStyle.CellPadding() {Top = 2.0f, Left = 2.0f, Right = 2.0f, Bottom = 2.0f},
                Alignment = new CellStyle.CellAlignment() { Horizontal = CellStyle.CellAlignment.HorizontalAlignment.Center, Vertical = CellStyle.CellAlignment.VerticalAlignment.Middle },
                Colors = new CellStyle.CellColors() { Back = Color.White },
                Rotation = CellStyle.CellRotation.None
            };
            this.DefaultCell = defaultCell;
        }

        public class TopLeftRightBottom
        {
            public float? Top;
            public float? Left;
            public float? Right;
            public float? Bottom;            
        }

        public class CellStyle
        {
            public CellStyle()
            {
                this.Font = new CellFont();
                this.Border = new BorderStyle() { Widths = new TopLeftRightBottom() };
                this.Span = new CellSpan();
                this.Padding = new CellPadding();
                this.Alignment = new CellAlignment();
                this.Colors = new CellColors();
            }

            #region Properties

            public CellFont Font { get; set; }
            public BorderStyle Border { get; set; }
            public CellSpan Span { get; set; }
            public CellPadding Padding { get; set; }
            public CellAlignment Alignment { get; set; }
            public CellRotation Rotation { get; set; }
            public CellColors Colors { get; set; }
            #endregion

            public class CellFont
            {
                public Font.FontFamily? Family;
                public float? Size;
                public FontType? Type;
                public enum FontType
                {
                    Normal = 0,
                    Bold = 1,
                    Italic = 2,
                    BoldItalic = 3,
                    Underline = 4,
                    StrikeThru = 8,
                    Undefined = -1
                }
                public Color? ForeColor;
                public Color? BackColor;
            }
            public class BorderStyle
            {
                public TopLeftRightBottom Widths { get; set; }
                public System.Drawing.Color? Color;
            }
            public class CellSpan
            {
                public int? Rows;
                public int? Cols;
            }
            public class CellPadding
            {
                public float? Top;
                public float? Left;
                public float? Right;
                public float? Bottom;
            }
            public class CellAlignment
            {
                public enum VerticalAlignment
                {
                    Bottom = Element.ALIGN_BOTTOM,
                    Middle = Element.ALIGN_MIDDLE,
                    Top = Element.ALIGN_TOP
                }
                public enum HorizontalAlignment
                {
                    Left = Element.ALIGN_LEFT,
                    Center = Element.ALIGN_CENTER,
                    Right = Element.ALIGN_RIGHT                    
                }
                public HorizontalAlignment? Horizontal;
                public VerticalAlignment? Vertical;
            }
            public enum CellRotation
            {
                None = 0,
                BottomToTop = 90,
                TopToBottom = -90
            }
            public class CellColors
            {
                public Color? Back;
            }
        }

        #region Properties

        private CellStyle DefaultCell { get; set; }

        #endregion

        #region Methods

        public void SetDefaultCell(CellStyle cellStyle)
        {
            if ( cellStyle != null )
            {
                if ( cellStyle.Font != null )
                {
                    this.DefaultCell.Font.Family    = cellStyle.Font.Family.HasValue ? cellStyle.Font.Family.Value : this.DefaultCell.Font.Family;
                    this.DefaultCell.Font.Size      = cellStyle.Font.Size.HasValue ? cellStyle.Font.Size.Value : this.DefaultCell.Font.Size; 
                    this.DefaultCell.Font.Type      = cellStyle.Font.Type.HasValue ? cellStyle.Font.Type.Value : this.DefaultCell.Font.Type; 
                    this.DefaultCell.Font.BackColor = cellStyle.Font.BackColor.HasValue ? cellStyle.Font.BackColor.Value : this.DefaultCell.Font.BackColor;
                    this.DefaultCell.Font.ForeColor = cellStyle.Font.ForeColor.HasValue ? cellStyle.Font.ForeColor.Value : this.DefaultCell.Font.ForeColor; 
                }
                if ( cellStyle.Border != null )
                {
                    this.DefaultCell.Border.Color    = cellStyle.Border.Color.HasValue ? cellStyle.Border.Color.Value : this.DefaultCell.Border.Color;
                    if (cellStyle.Border.Widths != null)
                    {
                        this.DefaultCell.Border.Widths.Top  = cellStyle.Border.Widths.Top.HasValue ? cellStyle.Border.Widths.Top.Value : this.DefaultCell.Border.Widths.Top.Value;
                        this.DefaultCell.Border.Widths.Bottom  = cellStyle.Border.Widths.Bottom.HasValue ? cellStyle.Border.Widths.Bottom.Value : this.DefaultCell.Border.Widths.Bottom.Value;
                        this.DefaultCell.Border.Widths.Left  = cellStyle.Border.Widths.Left.HasValue ? cellStyle.Border.Widths.Left.Value : this.DefaultCell.Border.Widths.Left.Value;
                        this.DefaultCell.Border.Widths.Right  = cellStyle.Border.Widths.Right.HasValue ? cellStyle.Border.Widths.Right.Value : this.DefaultCell.Border.Widths.Right.Value;
                    }
                }
                if ( cellStyle.Span != null )
                {
                    this.DefaultCell.Span.Cols      = cellStyle.Span.Cols.HasValue ? cellStyle.Span.Cols.Value : this.DefaultCell.Span.Cols;
                    this.DefaultCell.Span.Rows      = cellStyle.Span.Rows.HasValue ? cellStyle.Span.Rows.Value : this.DefaultCell.Span.Rows; 
                }
                if ( cellStyle.Padding != null )
                {
                    this.DefaultCell.Padding.Top    = cellStyle.Padding.Top.HasValue ? cellStyle.Padding.Top.Value : this.DefaultCell.Padding.Top;
                    this.DefaultCell.Padding.Left   = cellStyle.Padding.Left.HasValue ? cellStyle.Padding.Left.Value : this.DefaultCell.Padding.Left;
                    this.DefaultCell.Padding.Right  = cellStyle.Padding.Right.HasValue ? cellStyle.Padding.Right.Value : this.DefaultCell.Padding.Right;
                    this.DefaultCell.Padding.Bottom = cellStyle.Padding.Bottom.HasValue ? cellStyle.Padding.Bottom.Value : this.DefaultCell.Padding.Bottom;
                }
                if (cellStyle.Alignment != null)
                {
                    this.DefaultCell.Alignment.Horizontal   = cellStyle.Alignment.Horizontal.HasValue ? cellStyle.Alignment.Horizontal.Value : this.DefaultCell.Alignment.Horizontal.Value;    
                    this.DefaultCell.Alignment.Vertical     = cellStyle.Alignment.Vertical.HasValue ? cellStyle.Alignment.Vertical.Value : this.DefaultCell.Alignment.Vertical.Value;    
                }
                if ( cellStyle.Colors != null )
                {
                    this.DefaultCell.Colors.Back    = cellStyle.Colors.Back.HasValue ? cellStyle.Colors.Back.Value : this.DefaultCell.Colors.Back.Value;
                }
                this.DefaultCell.Rotation = cellStyle.Rotation;
            }
        }

        public void AddCell(PdfPTable table, string text, CellStyle style = null)
        {
            try 
	        {
                var font = GetFont( style );
                var cell = new PdfPCell
                {
                    Phrase = new Phrase(text, font),
                    VerticalAlignment = Element.ALIGN_MIDDLE,
                    HorizontalAlignment = Element.ALIGN_CENTER
                };

	            if ( style != null )
	            {
                    //cell.BorderWidth            = style.Border.Width.HasValue ? style.Border.Width.Value : this.DefaultCell.Border.Width.Value;
                    cell.BorderWidthTop = style.Border.Widths.Top.HasValue ? style.Border.Widths.Top.Value : this.DefaultCell.Border.Widths.Top.Value;
                    cell.BorderWidthLeft = style.Border.Widths.Left.HasValue ? style.Border.Widths.Left.Value : this.DefaultCell.Border.Widths.Left.Value;
                    cell.BorderWidthRight = style.Border.Widths.Right.HasValue ? style.Border.Widths.Right.Value : this.DefaultCell.Border.Widths.Right.Value;
	                cell.BorderWidthBottom = style.Border.Widths.Bottom.HasValue ? style.Border.Widths.Bottom.Value : this.DefaultCell.Border.Widths.Bottom.Value;
                    
                    cell.BorderColor            = new BaseColor( style.Border.Color.HasValue ? style.Border.Color.Value : this.DefaultCell.Border.Color.Value );
                    cell.BackgroundColor        = new BaseColor( style.Colors.Back.HasValue ? style.Colors.Back.Value : this.DefaultCell.Colors.Back.Value );
                    cell.Colspan                = style.Span.Cols.HasValue ? style.Span.Cols.Value : this.DefaultCell.Span.Cols.Value;  
                    cell.Rowspan                = style.Span.Rows.HasValue ? style.Span.Rows.Value : this.DefaultCell.Span.Rows.Value;
                    cell.PaddingTop             = style.Padding.Top.HasValue ? style.Padding.Top.Value : this.DefaultCell.Padding.Top.Value;
                    cell.PaddingLeft            = style.Padding.Left.HasValue ? style.Padding.Left.Value : this.DefaultCell.Padding.Left.Value;
                    cell.PaddingRight           = style.Padding.Right.HasValue ? style.Padding.Right.Value : this.DefaultCell.Padding.Right.Value;
                    cell.PaddingBottom          = style.Padding.Bottom.HasValue ? style.Padding.Bottom.Value : this.DefaultCell.Padding.Bottom.Value;
                    cell.Rotation               = (int)style.Rotation;
                    cell.HorizontalAlignment    = style.Alignment.Horizontal.HasValue? (int) style.Alignment.Horizontal.Value : (int)this.DefaultCell.Alignment.Horizontal.Value;
                    cell.VerticalAlignment      = style.Alignment.Vertical.HasValue? (int) style.Alignment.Vertical.Value : (int)this.DefaultCell.Alignment.Vertical.Value;
                }
                else
                {
                    //cell.BorderWidth            = this.DefaultCell.Border.Width.Value;
                    cell.BorderWidthTop         = this.DefaultCell.Border.Widths.Top.Value;
                    cell.BorderWidthBottom      = this.DefaultCell.Border.Widths.Bottom.Value;
                    cell.BorderWidthLeft        = this.DefaultCell.Border.Widths.Left.Value;
                    cell.BorderWidthRight       = this.DefaultCell.Border.Widths.Right.Value;

                    cell.BorderColor            = new BaseColor( this.DefaultCell.Border.Color.Value );
                    cell.BackgroundColor        = new BaseColor( this.DefaultCell.Colors.Back.Value );
                    cell.Colspan                = this.DefaultCell.Span.Cols.Value;  
                    cell.Rowspan                = this.DefaultCell.Span.Rows.Value;
                    cell.PaddingTop             = this.DefaultCell.Padding.Top.Value;
                    cell.PaddingLeft            = this.DefaultCell.Padding.Left.Value;
                    cell.PaddingRight           = this.DefaultCell.Padding.Right.Value;
                    cell.PaddingBottom          = this.DefaultCell.Padding.Bottom.Value;
                    cell.Rotation               = (int)this.DefaultCell.Rotation;
                    cell.HorizontalAlignment    = (int)this.DefaultCell.Alignment.Horizontal.Value;
                    cell.VerticalAlignment      = (int)this.DefaultCell.Alignment.Vertical.Value;
                }

                table.AddCell( cell );
	        }
	        catch (Exception)
	        {
		        throw;
	        }
        }
        public void AddCell(PdfPTable table, string text, CellStyle.CellFont.FontType fontType)
        {
            try 
	        {
                this.AddCell(table, text, new CellStyle() { Font = new CellStyle.CellFont() { Type = fontType } } );
	        }
	        catch (Exception)
	        {
		        throw;
	        }
        }
        public void AddCells(PdfPTable table, string[] values, CellStyle style = null)
        {
            //for(var i=0; i < values.Length; i++)
            //{
            //    this.AddCell(table, values[i], style);
            //}
            foreach (var text in values)
            {
                this.AddCell(table, text ?? " ", style);
            }
        }

        public void InsertImage(PdfPTable table, string filePath, System.Drawing.Bitmap image, float width, float height, CellStyle style)
        {
            try
            {
                //iTextSharp.text.Image img = iTextSharp.text.Image.GetInstance( HttpContext.Current.Server.MapPath(filePath) + "\\" + fileName );
                //iTextSharp.text.Image img = iTextSharp.text.Image.GetInstance(@"http://www.something.com/Images/myImage.jpg" );
                //iTextSharp.text.Image img = iTextSharp.text.Image.GetInstance( Formatter.ByteArray.ConvertirEnByteArray( Resources.SomeImage, System.Drawing.Imaging.ImageFormat.Bmp ) );

                if (image.IsNull())
                    image = Resources.Empty;
                var img = iTextSharp.text.Image.GetInstance(Formatter.ByteArray.ConvertirEnByteArray(image, System.Drawing.Imaging.ImageFormat.Bmp));
                    img.ScaleToFit(width, height);
                var cell = new PdfPCell( img );
                if ( style.IsNotNull() )
                {
                    //cell.BorderWidth        = style.Border.Width.HasValue ? style.Border.Width.Value : this.DefaultCell.Border.Width.Value;
                    cell.BorderWidthTop        = style.Border.Widths.Top.HasValue ? style.Border.Widths.Top.Value : this.DefaultCell.Border.Widths.Top.Value;
                    cell.BorderWidthBottom      = style.Border.Widths.Bottom.HasValue ? style.Border.Widths.Bottom.Value : this.DefaultCell.Border.Widths.Bottom.Value;
                    cell.BorderWidthLeft        = style.Border.Widths.Left.HasValue ? style.Border.Widths.Left.Value : this.DefaultCell.Border.Widths.Left.Value;
                    cell.BorderWidthRight       = style.Border.Widths.Right.HasValue ? style.Border.Widths.Right.Value : this.DefaultCell.Border.Widths.Right.Value;
                    
                    cell.BorderColor        = new BaseColor( style.Border.Color.HasValue ? style.Border.Color.Value : this.DefaultCell.Border.Color.Value );                    
                    cell.BackgroundColor    = new BaseColor( style.Colors.Back.HasValue ? style.Colors.Back.Value : this.DefaultCell.Colors.Back.Value );
                    cell.Colspan            = style.Span.Cols.HasValue ? style.Span.Cols.Value : this.DefaultCell.Span.Cols.Value;  
                    cell.Rowspan            = style.Span.Rows.HasValue ? style.Span.Rows.Value : this.DefaultCell.Span.Rows.Value;
                    cell.PaddingTop         = style.Padding.Top.HasValue ? style.Padding.Top.Value : this.DefaultCell.Padding.Top.Value;
                    cell.PaddingLeft        = style.Padding.Left.HasValue ? style.Padding.Left.Value : this.DefaultCell.Padding.Left.Value;
                    cell.PaddingRight       = style.Padding.Right.HasValue ? style.Padding.Right.Value : this.DefaultCell.Padding.Right.Value;
                    cell.PaddingBottom      = style.Padding.Bottom.HasValue ? style.Padding.Bottom.Value : this.DefaultCell.Padding.Bottom.Value;
                }
                else
                {
                    //cell.BorderWidth        = this.DefaultCell.Border.Width.Value;
                    cell.BorderWidthTop = this.DefaultCell.Border.Widths.Top.Value;
                    cell.BorderWidthBottom = this.DefaultCell.Border.Widths.Bottom.Value;
                    cell.BorderWidthLeft = this.DefaultCell.Border.Widths.Left.Value;
                    cell.BorderWidthRight = this.DefaultCell.Border.Widths.Right.Value;

                    cell.BorderColor        = new BaseColor( this.DefaultCell.Border.Color.Value );
                    cell.BackgroundColor    = new BaseColor( this.DefaultCell.Colors.Back.Value );
                    cell.Colspan            = this.DefaultCell.Span.Cols.Value;  
                    cell.Rowspan            = this.DefaultCell.Span.Rows.Value;
                    cell.PaddingTop         = this.DefaultCell.Padding.Top.Value;
                    cell.PaddingLeft        = this.DefaultCell.Padding.Left.Value;
                    cell.PaddingRight       = this.DefaultCell.Padding.Right.Value;
                    cell.PaddingBottom      = this.DefaultCell.Padding.Bottom.Value;
                }

                table.AddCell( cell );
            }
            catch (Exception)
            {
                throw;
            }
        }

        public static void CombinePDFs(string filename, IEnumerable<byte[]> contents)
        {
            using (var stream = new FileStream(filename, FileMode.Create))
            {
                var document = new Document();
                var pdf = new PdfCopy(document, stream);
                PdfReader reader = null;
                try
                {
                    document.Open();
                    foreach (var content in contents)
                    {
                        reader = new PdfReader(content);
                        pdf.AddDocument(reader);
                        reader.Close();
                    }
                }
                catch (Exception)
                {
                    if (reader != null)
                        reader.Close();
                }
                finally
                {
                    document.Close();
                }
            }
        }

        #endregion

        #region Helpers

        private Font GetFont(CellStyle style)
        {
            var font    = default(Font);
            var family  = this.DefaultCell.Font.Family.HasValue     ? this.DefaultCell.Font.Family.Value    : Font.FontFamily.HELVETICA;
            var size    = this.DefaultCell.Font.Size.HasValue       ? this.DefaultCell.Font.Size.Value      : 11f;
            var type    = this.DefaultCell.Font.Type.HasValue       ? (int)this.DefaultCell.Font.Type       : Font.NORMAL;
            var color   = this.DefaultCell.Font.ForeColor.HasValue  ? this.DefaultCell.Font.ForeColor.Value : Color.Black;
            try
            {
                if ( style != null )
                {
                    if ( style.Font != null )
                    {
                        family  = style.Font.Family.HasValue    ? style.Font.Family.Value       : this.DefaultCell.Font.Family.Value;
                        size    = style.Font.Size.HasValue      ? style.Font.Size.Value         : this.DefaultCell.Font.Size.Value;
                        type    = style.Font.Type.HasValue      ? (int)style.Font.Type.Value    : (int)this.DefaultCell.Font.Type.Value;
                        color   = style.Font.ForeColor.HasValue ? style.Font.ForeColor.Value    : this.DefaultCell.Font.ForeColor.Value;
                    }
                }
                font = new Font( family, size, type, new BaseColor( color ) );
            }
            catch (Exception)
            {
                throw;
            }
            return font;
        }

        #endregion
    }
}